﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Universum.Infrastructure.Persistence;
using Universum.Infrastructure.Persistence.Queries;
using Universum.Model.Domain;
using Universum.Model.Services;
using System.IO;

namespace Universum.Tests.Queries
{
	[TestClass]
	public class ResourceServiceTests
	{
		Guid id;
		
		Resource originalResource;

		[TestInitialize]
		public void on_intializing_a_new_test()
		{
			id = new Guid("11223345-2649-1212-2132-554456798211");
			originalResource = new Resource
					{
						ID = id,
						Owner = "admin",
						Path = "home/user",
						ContentType = "image/png"
					};

		}

		#region Arrange
		void setup_a_mock_that_handles_load_for_resource_id(ref Mock<IRepository> pRepositoryMock)
		{
			pRepositoryMock.Setup(
				on => on.Load<Resource>(id)).Returns(() =>
				{
					return originalResource ;
				})
				;

		}


		void setup_a_mock_that_returns_null(ref Mock<IRepository> repositoryMock)
		{
			repositoryMock.Setup(mock => mock.Load<Resource>(id))
				.Returns(()=>null);

		}

		void setup_a_mock_that_verifies_that_remove_is_called(ref Mock<IRepository> repositoryMock)
		{
			repositoryMock.Setup(rep => rep.Remove(originalResource)).Verifiable();

		}
		void setup_a_mock_on_fileSerice_to_return_false_on_exists_path(
			ref Mock<IFileService> fileService
			)
		{
			fileService = new Mock<IFileService>();
			fileService
				.Setup(serviceCallTo => serviceCallTo.FileExists(originalResource.Path))
				
				.Returns(false)
				.Verifiable()
				;
		}
		void setup_a_mock_on_fileService_to_return_true_on_exists_path(
			ref Mock<IFileService> fileService
			)
		{
			
			fileService
				.Setup(callOn => callOn.FileExists(originalResource.Path))
				.Returns(true)
				.Verifiable();
		}
		void setup_a_mock_on_fileService_to_return_aMemoryStream(
			ref Mock<IFileService> fileService)
		{
			fileService
				.Setup(onCallTo => onCallTo.GetStreamFor(originalResource.Path))
				.Returns(new MemoryStream(new byte[] { 0 }))
				.Verifiable();
		}
		#endregion


		[TestMethod]
		public void remove_resource_from_repository_if_it_is_not_found_on_the_fileSystem()

		{
			// Arrange
			Mock<IFileService> fileService = new Mock<IFileService>();
			Mock<IRepository> repositoryMock = new Mock<IRepository>();
			setup_a_mock_that_handles_load_for_resource_id(ref 
				repositoryMock);
			setup_a_mock_on_fileSerice_to_return_false_on_exists_path(
				ref fileService);
			
			FileResourceService fileResourceService =
				new FileResourceService(repositoryMock.Object, fileService.Object);		
			// Act	
			var resourceReturned = fileResourceService.FindById(id);
			// Assert
			resourceReturned.should_be_null();
			repositoryMock.VerifyAll(); // fails if was not called.

		}
		[TestMethod]
		public void return_requested_resource_if_its_found()
		{
			//Arrange
			Mock<IFileService> fileService = new Mock<IFileService>();
			Mock<IRepository> repositoryMock = new Mock<IRepository>();

			setup_a_mock_on_fileService_to_return_true_on_exists_path(ref fileService);
			setup_a_mock_on_fileService_to_return_aMemoryStream(ref fileService);
			setup_a_mock_that_handles_load_for_resource_id(ref repositoryMock);
			var fileRService = new FileResourceService(
				repositoryMock.Object,
				fileService.Object);
			//Act
			var resource = fileRService.FindById(id);

			//Assert
			resource.should_not_be_null();
			resource.Content.should_not_be_null();

		}
		[TestMethod]
		public void should_return_the_correct_resource_from_the_repository()
		{
			Mock<IRepository> repositoryMock = new Mock<IRepository>();

			setup_a_mock_that_handles_load_for_resource_id(ref repositoryMock);
			var resourceIs = repositoryMock.Object.Load<Resource>(id);
			resourceIs.should_not_be_null();
			resourceIs.should_not_be_null();
			resourceIs.Owner.should_be_equal_to("admin");

		}
		[TestMethod]
		public void should_return_null_if_no_items_are_found()
		{
			Mock<IRepository> repositoryMock = new Mock<IRepository>();

			setup_a_mock_that_returns_null(ref repositoryMock);
			var resultResource = repositoryMock.Object.Load<Resource>(
				id);
			resultResource.should_be_null();

		}

		[TestMethod]
		public void should_be_able_to_see_that_a_method_was_called()
		{
			Mock<IRepository> repositoryMock = new Mock<IRepository>();
			setup_a_mock_that_verifies_that_remove_is_called(ref repositoryMock);
			var mockedRepositoryInstance= repositoryMock.Object;
			mockedRepositoryInstance.Remove(originalResource);
			repositoryMock.VerifyAll();

		}

	}
}
